//
//  BroadcastCenter.swift
//  SwiftTools
//
//  Created by Samuel Richard Magny on 15-10-02.
//  Copyright © 2015 Samuel Richard Magny. All rights reserved.
//

import Cocoa

public class BroadcastCenter: NSObject {
    
    private static let _defaultCenter = BroadcastCenter()
    
    public typealias identifierType = String
    internal typealias registerArrayTupleType = (Selector, AnyObject)
    
    
    var broadcastRegister:Dictionary<identifierType, Array<registerArrayTupleType>> = [:]
    
    public func subscribe(receiver:AnyObject, selector aSelector: Selector, identifier:identifierType)
    {
        let newElement = (aSelector,receiver)
        if !broadcastRegister.keys.contains(identifier)
        {
            broadcastRegister[identifier] = [newElement]
        }
        else
        {
            broadcastRegister[identifier]?.append(newElement)
        }
    }
    
    public func unSubscribe(receiver:AnyObject, identifier:identifierType)
    {
        if var notifications = broadcastRegister[identifier]
        {
            var index:Int = 0;
            for notification in notifications
            {
                if notification.1 === receiver
                {
                    notifications.removeAtIndex(index)
                    broadcastRegister[identifier] = notifications
                    break;
                }
                
                index = index + 1
            }
        }
    }
    
    public static func defaultCenter() -> BroadcastCenter
    {
        return _defaultCenter
    }
    
    internal func receiversForIdentifier(identifier:identifierType) -> Array<registerArrayTupleType>?
    {
        if let notifications = broadcastRegister[identifier]
        {
            return notifications
        }
        
        return nil
    }
    
    public func post(broadcast:BroadcastNotification)
    {
        if let notifications = broadcastRegister[broadcast.identifier]
        {
            for notification in notifications
            {
                invoke(notification.0, on: notification.1, broadcast:broadcast)
            }
        }
        
    }
    
    public func postInBackgroundThread(broadcast:BroadcastNotification)
    {
        if let notifications = broadcastRegister[broadcast.identifier]
        {
            for notification in notifications
            {
                invokeInBackgroundThread(notification.0, on: notification.1, broadcast:broadcast)
            }
        }
    }
    
    private func invokeInBackgroundThread(selector:Selector, on target:AnyObject, broadcast:BroadcastNotification)
    {
        target.performSelectorInBackground(selector, withObject: broadcast)
    }
    
    private func invoke(selector:Selector, on target:AnyObject, broadcast:BroadcastNotification)
    {
        target.performSelector(selector, withObject: broadcast)
    }
}
